#!/usr/bin/env python
#coding:utf-8
#demo:pyside gui application communicate with multiprocessing.Process()

import sys,time
import multiprocessing as mp
import logging,logging.handlers
from PySide.QtCore import *
from PySide.QtGui import *

class mywindow(QWidget):
    refreshpv=Signal(str)

    def __init__(self,appargs,qlog,qtogui,lock,v1):
        super(mywindow, self).__init__()
        self.appargs=appargs
        self.qlog=qlog
        self.qtogui=qtogui
        self.lock=lock
        self.v1=v1

        self.initgui()
        self.refreshpv.connect(self.slotrefreshpv)

        self.thtest=sidethread(self.qtogui,self)
        self.thtest.start()
        self.qlog.put('pyside application started.')

        if isinstance(self.appargs['totalprogress'],int):
            print(self.appargs['totalprogress'],self.appargs['crtprogress'])
        else:
            print(self.appargs['totalprogress'].value,self.appargs['crtprogress'].value)

    def initgui(self):
        self.btntest=QPushButton('logging test')
        self.btntest.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)
        self.pgb=QProgressBar()
        self.pgb.setMaximum(self.appargs['totalprogress'].value)
        self.pgb.setMinimum(0)
        self.pgb.setValue(0)
        self.teinfo=QTextEdit()
        self.teinfo.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
        self.teinfo.append('information:')
        vbox=QVBoxLayout()
        vbox.addWidget(self.btntest)
        vbox.addWidget(self.pgb)
        vbox.addWidget(self.teinfo)
        self.setLayout(vbox)

        self.resize(600,400)

        #connect object's signal to slot
        self.btntest.clicked.connect(self.loggingtest)

    def loggingtest(self):
        try:
            itotal=300
            if isinstance(self.appargs['totalprogress'],int):
                self.appargs['totalprogress']=itotal
            else:
                with self.lock:
                    self.appargs['totalprogress'].value=itotal
            #self.pgb.setMaximum(itotal)
            for i in range(itotal):
                info='message come from pyside application for logging test.[%05d]' %i
                self.qlog.put(info)
                QApplication.processEvents()

        except Exception as ex:
            myprint(str(Exception)+'\n'+str(ex))

    def slotrefreshpv(self,logbf):
        self.pgb.setMaximum(int(self.appargs['totalprogress'].value))
        self.pgb.setValue(int(self.appargs['crtprogress'].value))
        self.teinfo.append(str(logbf))

    def closeEvent(self,event):
        self.qlog.put(None)
        self.qtogui.put(None)
        event.accept()

class sidethread(QThread):
    def __init__(self, qtogui, parent = None):
        QThread.__init__(self, parent)
        self.qtogui=qtogui
        self.parent=parent

    def run(self):
        while True:
            #t1=time.time()
            bf=self.qtogui.get()
            if bf is None:
                break
            #t2=time.time()
            #gui refresh can not too fast,otherwise gui application will crash.
            #if round((t2-t1),3)<=0.02:
            #    time.sleep(0.02)
            #self.parent.teinfo.append(str(bf))
            myprint('gui v1=%d' % self.parent.v1)
            if isinstance(self.parent.appargs['totalprogress'],int):
                myprint('gui thread::%d/%d' % (self.parent.appargs['crtprogress'],self.parent.appargs['totalprogress']))
                #self.parent.pgb.setMaximum(self.parent.appargs['totalprogress'])
                #self.parent.pgb.setValue(self.parent.appargs['crtprogress'])
            else:
                myprint('gui thread::%d/%d' % (self.parent.appargs['crtprogress'].value,self.parent.appargs['totalprogress'].value))
                #self.parent.pgb.setMaximum(self.parent.appargs['totalprogress'].value)
                #self.parent.pgb.setValue(self.parent.appargs['crtprogress'].value)
            self.parent.refreshpv.emit(bf)
            #QApplication.processEvents()

def logfunc(appargs,qlog,qtogui,lock,v1):
    if isinstance(appargs['totalprogress'],int):
        print(appargs['totalprogress'],appargs['crtprogress'])
    else:
        print(appargs['totalprogress'].value,appargs['crtprogress'].value)
    #log rotate works
    logger = setuplogger(appargs)
    while True:
        bf=qlog.get()
        if bf is None:
            break
        myprint('subprocess get() OK :: %s' % str(bf))
        qtogui.put('subprocess process OK :: %s' % str(bf))
        logger.info(bf)
        v1+=1
        myprint('subprocess v1=%d' % v1)
        if isinstance(appargs['totalprogress'],int):
            appargs['crtprogress']+=1
            myprint('logfunc::%d/%d' % (appargs['crtprogress'],appargs['totalprogress']))
        else:
            with lock:
                appargs['crtprogress'].value+=1
            myprint('logfunc::%d/%d' % (appargs['crtprogress'].value,appargs['totalprogress'].value))

    myprint('subprocess exit.')

def setuplogger(argsdict):
    LOGGINGLEVEL = {
        'notset': logging.NOTSET,
        'debug': logging.DEBUG,
        'info': logging.INFO,
        'warning': logging.WARNING,
        'error': logging.ERROR,
        'critical': logging.CRITICAL,
        }
    logfn=argsdict['logfilename']
    loglevel=LOGGINGLEVEL[argsdict['loglevel']]
    # setup logger object
    mylogger = logging.getLogger(argsdict['loggername'])
    # set log level
    mylogger.setLevel(loglevel)
    # handler
    handler = logging.handlers.RotatingFileHandler(logfn, maxBytes=argsdict['maxlogsize'], backupCount=argsdict['backupcount'])
    formatter =  logging.Formatter('%(asctime)s - %(name)s - %(levelname)s :: %(message)s'   )
    handler.setFormatter(formatter)
    # add handler to logger
    mylogger.addHandler(handler)
    # return logger object
    return mylogger

def myprint(obj, end='\n'):
    sys.stdout.write(str(obj) + end)

def startlog(appargs,qlog,qtogui,lock,v1):
    plog=mp.Process(target=logfunc,args=(appargs,qlog,qtogui,lock,v1))
    plog.start()
    return plog

def startgui(appargs,qlog,qtogui,lock,v1):
    app = QApplication(sys.argv)
    window = mywindow(appargs,qlog,qtogui,lock,v1)
    window.show()
    app.exec_()

def main():
    qlog=mp.Queue()
    qtogui=mp.Queue()
    lock=mp.Lock()
    appargs={   'loggername': 'app',
                'logfilename': 'app.log',
                'loglevel': 'debug',
                'maxlogsize': 50000,   #50kb
                'backupcount': 3,
                #'totalprogress':0,
                #'crtprogress':0,
                'totalprogress':mp.Value('i'),
                'crtprogress':mp.Value('i'),
            }
    #appargs=mp.Manager().dict(appargs)
    v1=0
    if isinstance(appargs['totalprogress'],int):
        appargs['totalprogress']=0
        appargs['crtprogress']=0
    else:
        appargs['totalprogress'].value=0
        appargs['crtprogress'].value=0

    plog=startlog(appargs,qlog,qtogui,lock,v1)
    startgui(appargs,qlog,qtogui,lock,v1)

if __name__ == '__main__':
    main()
